新手——win32程序的半生(CreateProcess)
工具
1、静态分析:IDA PRO
2、动态分析:Ollydbg/X32dbg/windbg
3、ARK工具:PCHunter
环境
1、虚拟机:VMware WORKSTATION 14 PRO
2、系统版本:win7专业版
知识背景
1、Windows的应用层基础知识:《Windows核心编程》
2、Windows的内核的基础知识:《Windows内核情景分析》
目标
研究win7系统下通过CreateProcess所创建的进程的所有函数执行流程(R3到R0的函数调用的大致整体流程)
思路
1、进程的本质,有哪些基本内容,需要哪些资源?
答:
本质:一个程序实际还是一段数据,管理的方式还是目录+内容,即内核对象+程序空间,以内核中的EPROCESS为目录,到CR3衍生的用户的虚拟地址空间的PE文件映像。
内容:
(1)一个进程会有一个系统分配的主线程主要运行代码。
(2)有一段虚拟内存空间,里面映射着PE文件内容。
(3)对应的一个内核对象,EPROCESS结构体。
2、R3环和R0的函数分别是如何调用的,分别有哪些和进程相关的函数?
答:
R3环:
CreateProcess
OpenProcess
CreateFile.......
R3环下有程序主动调用API,dll可以看做是R3下底层,API的简单实现在其中体现,dll中还会为进入R0环做一些准备工作。
R0环:
NTCreateProcess
NTCreateUserProcess........
R0环下通过ETHREAD结构的ServiceTable找到SSDT或ShadowSSDT,通过R3环准备的参数和索引来进行函数调用。
ps:Wows系统设计思路也是面向对象,所以如果把函数当成对象来看其实每个函数都是由其它得函数组成的。
CreateProcessW ==> CreateProcessInternalW ==> ZwCreateUserProcess ==> KiFastSystemCall ==> KiFastCallEntry ==> NtCreateUserProcess
3.R3环如何切换到R0环,R0如何返回R3环?
答:
(1)int 0X2E:
老版的进入方式,通过中断门主动调用KiSystemService来完成系统服务调用,和int 3对应KiTrap03类似。
KiSystemCallExit:iret返回
(2)SYSENTER:
较新的进入方式,通过该特权指令切换寄存器(EIP/SS/CS/ESP)来进入R0环,KiSystemCallExit2:SYSEXIT返回
4、R0环调用函数的索引如何获取?
答:
系统在进入R0环之前就做了很多检查和准备,例如:后期用到的索引就是在进入R0环之前就存储在EAX寄存器中,进入R0环只会切换关键寄存器来达到切换地址的目的,而EAX的值不会变化,索引就可以在R0下被访问到。
知识点
1.进程的创建流程。
2.动态链接库的调用。
3.系统服务描述符表的调用。
4.进程的虚拟地址空间(CR3寄存器)。
5.内核对象,例如:EPROCESS(据说搞定这个结构体就相当于搞定了大半个windows系统)、ETHREAD、KPCR、KPCRB。
6.R3环和R0环的交互。
分许步骤
1、整理以上知识点就得到了如下分析流程:
2、编写程序
通过CreateProcess创建一个目标进程
int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
BOOL bRet = CreateProcess(Path,NULL,NULL,NULL,FALSE,NULL,NULL,NULL,&si,&pi);
return 0;
}
3、调试程序(R3/R0)
3.1 R3环
OD调试R3下调试程序得到如下流程:
R3-1:CreateProcessW(main函数)
R3-2: CreateProcessInternalW(Kernel.dll模块)
1:ZwCreateUserProcess
2:KiFastSystemCall
3:SYSENTER
4.ZwResumeThread
R3-3:_CheckEsp
ps:其实可以直接在IDA中直接查看Kernel32.dll的函数实现。
3.2 R0环
R0环下windbg调式对新手用户并不友好,故而只用它找到CreateUserProcess的函数地址就可,然后在IDA中查看CreateUserProcess 的具体实现。
分析时尽量保证SSDT没有被HOOK,减少不必要的干扰。(找到函数的具体反汇编后就看个人的汇编的熟练程度了)
公式如下:
==> 偏移 = 函数地址-加载基址(ntkrnlpa.exe)
==> IDA的函数地址 = 偏移+0x400000(默认加载基址)。
PCHunter查看
1.ntkrnlpa的加载基址:0x84048000
2.SSDT 表中 CreateUserProcess 的原始函数地址:0x84298DE0
windbg调试:
1.dd KeServiceDescriptorTable
2.dds 840b76f0 +5d*4
IDA查看:
函数地址 = 0x8429dde0-0x84048000 + 0x400000 = 0x655DE0
1.NtCreateUserProcess未导出:
2.对比IDA和windbg的反汇编的函数内容
IDA
windbg
ps:可以将一个程序的组成看成:函数+执行逻辑,如果将系统看成一个巨大无比的程序,那么分析它也是可以从这两方面入手。
本次只是简单的分析了一个函数的执行流程,期间的函数实现会在开新贴进行具体分析,如:CreateProcessInternalW、NtCreateUserProcess、KiFastCallEntry等。
总结
总之分析学习一项比较庞大的东西的时候,我觉的要观察它的几个主要行为作为主线,然后在主线中慢慢的发展一些支线来加深自己的理解,对我而言是提升比较快的方式。
例如:学习Windows系统时分R3/R0去拆解,然后以进程的整个生命的生存周期为例子,利用现有的知识量去去实践去拓展。
所以就有了这篇帖子的诞生,算是为以后学习内核或是其他windowsAPI调用亦或是其他的一些事物提供一个思路,我不是方法论的崇拜者,但是好的方法、习惯的确可以事半功倍。
ps:~~共勉~~轻喷~~
本文由看雪论坛 Weaving 原创
转载请注明来自看雪社区
往期热门阅读:
扫描二维码关注我们,更多干货等你来拿!